﻿using KwaiXiaoDian.OpenApi.Models;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;
using SSharing.Frameworks.NetCore.Common.Extends;
using System;
using System.Diagnostics;
using System.IO;
using System.Text;
using System.Threading.Tasks;

namespace KwaiXiaoDian.OpenApi.Middlewares
{
    /// <summary>
    /// 请求日志中间件
    /// </summary>
    public class LoggingRequestMiddleware : IMiddleware
    {
        private readonly ILogger<LoggingRequestMiddleware> _logger;

        /// <summary>
        /// 
        /// </summary>
        /// <param name="logger"></param>
        public LoggingRequestMiddleware(ILogger<LoggingRequestMiddleware> logger)
        {
            _logger = logger;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="context"></param>
        /// <param name="_next"></param>
        /// <returns></returns>
        public async Task InvokeAsync(HttpContext context, RequestDelegate _next)
        {
            context.Request.EnableBuffering();
            var originalBody = context.Response.Body;

            var rq = await GetRequest(context);
            var rs = string.Empty;

            var sw = Stopwatch.StartNew();
            using (var ms = new MemoryStream())
            {
                context.Response.Body = ms;

                //传递给下一个中间件
                await _next(context);

                rs = await GetResponse(context);

                await ms.CopyToAsync(originalBody);
            }
            sw.Stop();

            var request = context.Request;
            var dics = request.RouteValues;

            if (!dics.HasValue())
            {
                return;
            }
            var sb = new StringBuilder();

            //method url
            sb.Append($"Method:{request.Method} {request.Host.Value + request.Path.Value + request.QueryString}");
            sb.Append(Environment.NewLine);

            //header
            var keys = context.Request.Headers.Keys;
            foreach (var key in keys)
            {
                var val = context.Request.Headers[key];
                sb.Append($"{key}: {val.ToString()}{ Environment.NewLine}");
            }

            //body
            sb.Append(Environment.NewLine);
            sb.Append(rq);

            object action = string.Empty;
            object controller = string.Empty;
            dics.TryGetValue("action", out action);
            dics.TryGetValue("controller", out controller);

            //记录请求日志
            var xmlLog = new XmlLog
            {
                ClassName = controller.ToString(),
                MethodName = action.ToString(),
                RQ = sb.ToString(),
                RS = rs,
                Duration = sw.ElapsedMilliseconds,
                Source = "KwaiXiaoDianApi",
                SystemCode = "KwaiXiaoDian"
            };
            _logger.LogInformation(xmlLog.ToJson());
        }

        /// <summary>
        /// 获取请求
        /// </summary>
        /// <param name="context"></param>
        /// <returns></returns>
        public static async Task<string> GetRequest(HttpContext context)
        {
            var request = context.Request;
            //此处的流不能关闭，否则管道中无法使用
            var sr = new StreamReader(request.Body, Encoding.UTF8);
            var content = await sr.ReadToEndAsync();
            request.Body.Position = 0;
            return content;
        }

        /// <summary>
        /// 获取响应
        /// </summary>
        /// <param name="context"></param>
        /// <returns></returns>
        public static async Task<string> GetResponse(HttpContext context)
        {
            var response = context.Response;
            //此处的流不能关闭，否则管道中无法使用
            response.Body.Position = 0;
            var sr = new StreamReader(response.Body, Encoding.Default);
            var content = $"httpcode:{response.StatusCode} {Environment.NewLine}{Environment.NewLine} { sr.ReadToEnd()}";
            response.Body.Position = 0;
            return content;
        }
    }
}
